/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


// r_debug.cpp -- back-end debug rendering


#include "r_local.h"


/*
 ==================
 RB_ShowDepth
 ==================
*/
static void RB_ShowDepth (void){

	float	*buffer;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor3f(1.0f, 1.0f, 1.0f);

	// Read the depth buffer
	buffer = (float *)Mem_Alloc(backEnd.viewParms.width * backEnd.viewParms.height * sizeof(float), TAG_TEMP);

	qglReadPixels(backEnd.viewParms.x, backEnd.viewParms.y, backEnd.viewParms.width, backEnd.viewParms.height, GL_DEPTH_COMPONENT, GL_FLOAT, buffer);

	// Set the raster position
	qglMatrixMode(GL_PROJECTION);
	qglPushMatrix();
	qglLoadIdentity();
	qglOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);

	qglMatrixMode(GL_MODELVIEW);
	qglPushMatrix();
	qglLoadIdentity();

	qglRasterPos2i(0, 0);

	qglMatrixMode(GL_MODELVIEW);
	qglPopMatrix();

	qglMatrixMode(GL_PROJECTION);
	qglPopMatrix();

	// Draw the depth buffer
	qglDrawPixels(backEnd.viewParms.width, backEnd.viewParms.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

	Mem_Free(buffer);

	// Check for errors
	if (!r_ignoreGLErrors->integerValue)
		GL_CheckForErrors();
}

/*
 ==================
 RB_ShowOverdraw
 ==================
*/
static void RB_ShowOverdraw (int numDrawMeshes, drawMesh_t *drawMeshes, bool ambient, bool fog){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glIndex_t	*indices;
	glVertex_t	*vertices;
	stage_t		*stage, *bumpStage, *diffuseStage, *specularStage;
	int			passes;
	int			i, j, n;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);
	GL_DepthFunc(GL_LEQUAL);

	GL_Enable(GL_STENCIL_TEST);
	GL_StencilFunc(GL_ALWAYS, 0, 255);
	GL_StencilOp(GL_KEEP, GL_KEEP, GL_INCR);

	GL_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(255);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Count number of passes
		if (fog)
			passes = 1;
		else {
			passes = 0;

			bumpStage = diffuseStage = specularStage = NULL;

			for (n = 0, stage = backEnd.material->stages; n < backEnd.material->numStages; n++, stage++){
				if (!backEnd.material->expressionRegisters[stage->conditionRegister])
					continue;

				switch (stage->lighting){
				case SL_AMBIENT:
					if (ambient)
						passes++;

					break;
				case SL_BUMP:
					if (bumpStage){
						if (!ambient)
							passes++;
					}

					bumpStage = stage;
					diffuseStage = NULL;
					specularStage = NULL;

					break;
				case SL_DIFFUSE:
					if (bumpStage && diffuseStage){
						if (!ambient)
							passes++;
					}

					diffuseStage = stage;

					break;
				case SL_SPECULAR:
					if (bumpStage && specularStage){
						if (!ambient)
							passes++;
					}

					specularStage = stage;

					break;
				}
			}

			if (bumpStage || diffuseStage || specularStage){
				if (!ambient)
					passes++;
			}
		}

		// Add to overdraw
		vertices = backEnd.vertices;

		if (ambient)
			RB_Deform();

		for (n = 0; n < passes; n++){
			indices = backEnd.indices;

			qglBegin(GL_TRIANGLES);
			for (j = 0; j < backEnd.numIndices; j += 3){
				qglVertex3fv(vertices[indices[0]].xyz.ToFloatPtr());
				qglVertex3fv(vertices[indices[1]].xyz.ToFloatPtr());
				qglVertex3fv(vertices[indices[2]].xyz.ToFloatPtr());

				indices += 3;
			}
			qglEnd();
		}

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowShadowCount
 ==================
*/
static void RB_ShowShadowCount (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t			*drawMesh;
	material_t			*material;
	entity_t			*entity;
	meshType_t			type;
	bool				caps;
	glIndex_t			*indices;
	glShadowVertex_t	*vertices;
	odVec4				projected;
	int					i, j, k;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Enable(GL_POLYGON_OFFSET_FILL);
	GL_PolygonOffset(r_shadowOffsetFactor->floatValue, r_shadowOffsetUnits->floatValue);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);
	GL_DepthFunc(GL_LEQUAL);

	GL_Enable(GL_STENCIL_TEST);
	GL_StencilFunc(GL_ALWAYS, 0, 255);
	GL_StencilOp(GL_KEEP, GL_INCR, GL_INCR);

	GL_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(255);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Skip static or dynamic shadows as needed
		if (entity == backEnd.scene->worldEntity){
			if (r_showShadowCount->integerValue == 3)
				continue;
		}
		else {
			if (r_showShadowCount->integerValue == 2)
				continue;
		}

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the light state for this entity
		RB_SetLightState(entity, backEnd.light, NULL, NULL);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = true;
		backEnd.shadowCaps = caps;

		// Batch the mesh
		RB_BatchMeshShadow(type, drawMesh->mesh);

		// Render the shadow volumes
		indices = backEnd.shadowIndices;
		vertices = backEnd.shadowVertices;

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 6){
			for (k = 0; k < 6; k++){
				if (indices[k] & 1){
					projected[0] = vertices[indices[k]].xyzw[0] - backEnd.localParms.lightOrigin[0];
					projected[1] = vertices[indices[k]].xyzw[1] - backEnd.localParms.lightOrigin[1];
					projected[2] = vertices[indices[k]].xyzw[2] - backEnd.localParms.lightOrigin[2];
					projected[3] = 0.0f;

					qglVertex4fv(projected.ToFloatPtr());
				}
				else
					qglVertex4fv(vertices[indices[k]].xyzw.ToFloatPtr());
			}

			indices += 6;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowLightCount
 ==================
*/
static void RB_ShowLightCount (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glIndex_t	*indices;
	glVertex_t	*vertices;
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);
	GL_DepthFunc(GL_EQUAL);

	GL_Enable(GL_STENCIL_TEST);
	GL_StencilFunc(GL_ALWAYS, 0, 255);

	if (r_showLightCount->integerValue == 1)
		GL_StencilOp(GL_KEEP, GL_KEEP, GL_INCR);
	else
		GL_StencilOp(GL_KEEP, GL_INCR, GL_INCR);

	GL_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(255);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Add to light count
		indices = backEnd.indices;
		vertices = backEnd.vertices;

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 3){
			qglVertex3fv(vertices[indices[0]].xyz.ToFloatPtr());
			qglVertex3fv(vertices[indices[1]].xyz.ToFloatPtr());
			qglVertex3fv(vertices[indices[2]].xyz.ToFloatPtr());

			indices += 3;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowLightVolume
 ==================
*/
static void RB_ShowLightVolume (void){

	int		cornerIndices[6][4] = {{3, 2, 6, 7}, {0, 1, 5, 4}, {2, 3, 1, 0}, {4, 5, 7, 6}, {1, 3, 7, 5}, {2, 0, 4, 6}};
	int		i;

	// Set the GL state
	GL_LoadMatrix(GL_MODELVIEW, backEnd.viewParms.modelviewMatrix);

	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	GL_DepthRange(0.0f, 1.0f);

	if (r_showLightVolumes->integerValue != 2){
		// Set the GL state
		GL_Enable(GL_POLYGON_OFFSET_FILL);
		GL_PolygonOffset(r_offsetFactor->floatValue, r_offsetUnits->floatValue);

		GL_Enable(GL_BLEND);
		GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		GL_Enable(GL_DEPTH_TEST);
		GL_DepthFunc(GL_LEQUAL);

		qglColor4f(backEnd.light->materialParms[0], backEnd.light->materialParms[1], backEnd.light->materialParms[2], 0.5f);

		// Draw it
		qglBegin(GL_QUADS);
		for (i = 0; i < 6; i++){
			qglVertex3fv(backEnd.light->data.corners[cornerIndices[i][0]].ToFloatPtr());
			qglVertex3fv(backEnd.light->data.corners[cornerIndices[i][1]].ToFloatPtr());
			qglVertex3fv(backEnd.light->data.corners[cornerIndices[i][2]].ToFloatPtr());
			qglVertex3fv(backEnd.light->data.corners[cornerIndices[i][3]].ToFloatPtr());
		}
		qglEnd();
	}

	if (r_showLightVolumes->integerValue != 1){
		// Set the GL state
		GL_Disable(GL_POLYGON_OFFSET_FILL);

		GL_Disable(GL_BLEND);

		GL_Disable(GL_DEPTH_TEST);

		qglColor3f(backEnd.light->materialParms[0], backEnd.light->materialParms[1], backEnd.light->materialParms[2]);

		// Draw it
		qglBegin(GL_LINE_LOOP);
		qglVertex3fv(backEnd.light->data.corners[0].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[2].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[3].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[1].ToFloatPtr());
		qglEnd();

		qglBegin(GL_LINE_LOOP);
		qglVertex3fv(backEnd.light->data.corners[4].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[6].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[7].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[5].ToFloatPtr());
		qglEnd();

		qglBegin(GL_LINES);
		qglVertex3fv(backEnd.light->data.corners[0].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[4].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[1].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[5].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[2].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[6].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[3].ToFloatPtr());
		qglVertex3fv(backEnd.light->data.corners[7].ToFloatPtr());
		qglEnd();
	}

	// Check for errors
	if (!r_ignoreGLErrors->integerValue)
		GL_CheckForErrors();
}

/*
 ==================
 RB_ShowLightScissors
 ==================
*/
static void RB_ShowLightScissors (void){

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor3f(backEnd.light->materialParms[0], backEnd.light->materialParms[1], backEnd.light->materialParms[2]);

	// Draw it
	qglBegin(GL_LINE_LOOP);
	qglVertex2i(backEnd.light->scissorX, backEnd.light->scissorY);
	qglVertex2i(backEnd.light->scissorX + backEnd.light->scissorWidth, backEnd.light->scissorY);
	qglVertex2i(backEnd.light->scissorX + backEnd.light->scissorWidth, backEnd.light->scissorY + backEnd.light->scissorHeight);
	qglVertex2i(backEnd.light->scissorX, backEnd.light->scissorY + backEnd.light->scissorHeight);
	qglEnd();

	// Check for errors
	if (!r_ignoreGLErrors->integerValue)
		GL_CheckForErrors();
}

/*
 ==================
 RB_ShowShadowTris
 ==================
*/
static void RB_ShowShadowTris (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t			*drawMesh;
	material_t			*material;
	entity_t			*entity;
	meshType_t			type;
	bool				caps;
	glIndex_t			*indices;
	glShadowVertex_t	*vertices;
	odVec4				projected;
	int					i, j, k;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	if (r_showShadowTris->integerValue == 1){
		GL_Enable(GL_DEPTH_TEST);
		GL_DepthFunc(GL_LEQUAL);
	}
	else
		GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor3f(1.0f, 0.0f, 1.0f);

	qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	if (r_showShadowTris->integerValue == 1){
		GL_Enable(GL_POLYGON_OFFSET_LINE);
		GL_PolygonOffset(r_offsetFactor->floatValue, r_offsetUnits->floatValue);
	}

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the light state for this entity
		RB_SetLightState(entity, backEnd.light, NULL, NULL);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = true;
		backEnd.shadowCaps = caps;

		// Batch the mesh
		RB_BatchMeshShadow(type, drawMesh->mesh);

		// Render the shadow tris
		indices = backEnd.shadowIndices;
		vertices = backEnd.shadowVertices;

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 6){
			for (k = 0; k < 6; k++){
				if (indices[k] & 1){
					projected[0] = vertices[indices[k]].xyzw[0] - backEnd.localParms.lightOrigin[0];
					projected[1] = vertices[indices[k]].xyzw[1] - backEnd.localParms.lightOrigin[1];
					projected[2] = vertices[indices[k]].xyzw[2] - backEnd.localParms.lightOrigin[2];
					projected[3] = 0.0f;

					qglVertex4fv(projected.ToFloatPtr());
				}
				else
					qglVertex4fv(vertices[indices[k]].xyzw.ToFloatPtr());
			}

			indices += 6;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}

	// Restore the GL state
	if (r_showShadowTris->integerValue == 1)
		GL_Disable(GL_POLYGON_OFFSET_LINE);

	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

/*
 ==================
 RB_ShowShadowVolumes
 ==================
*/
static void RB_ShowShadowVolumes (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t			*drawMesh;
	material_t			*material;
	entity_t			*entity;
	meshType_t			type;
	bool				caps;
	glIndex_t			*indices;
	glShadowVertex_t	*vertices;
	odVec4				projected;
	int					i, j, k;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Enable(GL_POLYGON_OFFSET_FILL);
	GL_PolygonOffset(r_shadowOffsetFactor->floatValue, r_shadowOffsetUnits->floatValue);

	GL_Enable(GL_BLEND);
	GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);
	GL_DepthFunc(GL_LEQUAL);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor4f(0.0f, 1.0f, 1.0f, 0.5f);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the light state for this entity
		RB_SetLightState(entity, backEnd.light, NULL, NULL);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = true;
		backEnd.shadowCaps = caps;

		// Batch the mesh
		RB_BatchMeshShadow(type, drawMesh->mesh);

		// Render the shadow volumes
		indices = backEnd.shadowIndices;
		vertices = backEnd.shadowVertices;

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 6){
			for (k = 0; k < 6; k++){
				if (indices[k] & 1){
					projected[0] = vertices[indices[k]].xyzw[0] - backEnd.localParms.lightOrigin[0];
					projected[1] = vertices[indices[k]].xyzw[1] - backEnd.localParms.lightOrigin[1];
					projected[2] = vertices[indices[k]].xyzw[2] - backEnd.localParms.lightOrigin[2];
					projected[3] = 0.0f;

					qglVertex4fv(projected.ToFloatPtr());
				}
				else
					qglVertex4fv(vertices[indices[k]].xyzw.ToFloatPtr());
			}

			indices += 6;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowShadowSilhouettes
 ==================
*/
static void RB_ShowShadowSilhouettes (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t			*drawMesh;
	material_t			*material;
	entity_t			*entity;
	meshType_t			type;
	bool				caps;
	glIndex_t			*indices;
	glShadowVertex_t	*vertices;
	int					i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor3f(1.0f, 1.0f, 0.0f);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the light state for this entity
		RB_SetLightState(entity, backEnd.light, NULL, NULL);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = true;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMeshShadow(type, drawMesh->mesh);

		// Render the shadow silhouettes
		indices = backEnd.shadowIndices;
		vertices = backEnd.shadowVertices;

		qglBegin(GL_LINES);
		for (j = 0; j < backEnd.numIndices; j += 6){
			qglVertex4fv(vertices[indices[0]].xyzw.ToFloatPtr());
			qglVertex4fv(vertices[indices[1]].xyzw.ToFloatPtr());

			indices += 6;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowVertexColors
 ==================
*/
static void RB_ShowVertexColors (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glIndex_t	*indices;
	glVertex_t	*vertices;
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Enable(GL_BLEND);
	GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Render the vertex colors
		indices = backEnd.indices;
		vertices = backEnd.vertices;

		RB_Deform();

		if (backEnd.material->flags & MF_POLYGONOFFSET){
			GL_Enable(GL_POLYGON_OFFSET_FILL);
			GL_PolygonOffset(r_offsetFactor->floatValue, r_offsetUnits->floatValue);
		}
		else
			GL_Disable(GL_POLYGON_OFFSET_FILL);

		if (backEnd.material->coverage == MC_TRANSLUCENT)
			GL_DepthFunc(GL_LEQUAL);
		else
			GL_DepthFunc(GL_EQUAL);

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 3){
			qglColor4ubv(vertices[indices[0]].color);
			qglVertex3fv(vertices[indices[0]].xyz.ToFloatPtr());

			qglColor4ubv(vertices[indices[1]].color);
			qglVertex3fv(vertices[indices[1]].xyz.ToFloatPtr());

			qglColor4ubv(vertices[indices[2]].color);
			qglVertex3fv(vertices[indices[2]].xyz.ToFloatPtr());

			indices += 3;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowTangentSpace
 ==================
*/
static void RB_ShowTangentSpace (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glIndex_t	*indices;
	glVertex_t	*vertices;
	odVec3		color[3];
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Enable(GL_BLEND);
	GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Skip if it doesn't have tangent space
		if (type != MESH_SURFACE && type != MESH_MODEL && type != MESH_FOLIAGE)
			continue;

		// Skip if it has a deform that invalidates the tangent space
		if (material->deform == DFRM_SPRITE || material->deform == DFRM_TUBE || material->deform == DFRM_FLARE)
			continue;

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Render the tangent space
		indices = backEnd.indices;
		vertices = backEnd.vertices;

		RB_Deform();

		if (backEnd.material->flags & MF_POLYGONOFFSET){
			GL_Enable(GL_POLYGON_OFFSET_FILL);
			GL_PolygonOffset(r_offsetFactor->floatValue, r_offsetUnits->floatValue);
		}
		else
			GL_Disable(GL_POLYGON_OFFSET_FILL);

		if (backEnd.material->coverage == MC_TRANSLUCENT)
			GL_DepthFunc(GL_LEQUAL);
		else
			GL_DepthFunc(GL_EQUAL);

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 3){
			// Select color from tangent or normal vector
			switch (r_showTangentSpace->integerValue){
			case 1:
				color[0] = vertices[indices[0]].tangents[0] * 0.5f;
				color[1] = vertices[indices[1]].tangents[0] * 0.5f;
				color[2] = vertices[indices[2]].tangents[0] * 0.5f;

				break;
			case 2:
				color[0] = vertices[indices[0]].tangents[1] * 0.5f;
				color[1] = vertices[indices[1]].tangents[1] * 0.5f;
				color[2] = vertices[indices[2]].tangents[1] * 0.5f;

				break;
			default:
				color[0] = vertices[indices[0]].normal * 0.5f;
				color[1] = vertices[indices[1]].normal * 0.5f;
				color[2] = vertices[indices[2]].normal * 0.5f;

				break;
			}

			qglColor4f(0.5f + color[0][0], 0.5f + color[0][1], 0.5f + color[0][2], 0.5f);
			qglVertex3fv(vertices[indices[0]].xyz.ToFloatPtr());

			qglColor4f(0.5f + color[1][0], 0.5f + color[1][1], 0.5f + color[1][2], 0.5f);
			qglVertex3fv(vertices[indices[1]].xyz.ToFloatPtr());

			qglColor4f(0.5f + color[2][0], 0.5f + color[2][1], 0.5f + color[2][2], 0.5f);
			qglVertex3fv(vertices[indices[2]].xyz.ToFloatPtr());

			indices += 3;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowTris
 ==================
*/
static void RB_ShowTris (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glIndex_t	*indices;
	glVertex_t	*vertices;
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	if (r_showTris->integerValue == 1){
		GL_Enable(GL_DEPTH_TEST);
		GL_DepthFunc(GL_LEQUAL);
	}
	else
		GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor3f(1.0f, 1.0f, 1.0f);

	qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	if (r_showTris->integerValue == 1){
		GL_Enable(GL_POLYGON_OFFSET_LINE);
		GL_PolygonOffset(r_offsetFactor->floatValue, r_offsetUnits->floatValue);
	}

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Render the tris
		indices = backEnd.indices;
		vertices = backEnd.vertices;

		RB_Deform();

		qglBegin(GL_TRIANGLES);
		for (j = 0; j < backEnd.numIndices; j += 3){
			qglVertex3fv(vertices[indices[0]].xyz.ToFloatPtr());
			qglVertex3fv(vertices[indices[1]].xyz.ToFloatPtr());
			qglVertex3fv(vertices[indices[2]].xyz.ToFloatPtr());

			indices += 3;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}

	// Restore the GL state
	if (r_showTris->integerValue == 1)
		GL_Disable(GL_POLYGON_OFFSET_LINE);

	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

/*
 ==================
 RB_ShowNormals
 ==================
*/
static void RB_ShowNormals (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glVertex_t	*vertices;
	odVec3		point;
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Skip if it has a deform that invalidates the normals
		if (material->deform == DFRM_FLARE)
			continue;

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Render the normals
		vertices = backEnd.vertices;

		RB_Deform();

		qglBegin(GL_LINES);
		for (j = 0; j < backEnd.numVertices; j++){
			// Normal
			point = vertices->xyz + vertices->normal * r_showNormals->floatValue;

			qglColor3f(0.0f, 0.0f, 1.0f);
			qglVertex3fv(vertices->xyz.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			// Skip tangents if it doesn't have them
			if (type != MESH_SURFACE && type != MESH_MODEL && type != MESH_FOLIAGE){
				vertices++;
				continue;
			}

			// Skip tangents if it has a deform that invalidates them
			if (material->deform == DFRM_SPRITE || material->deform == DFRM_TUBE){
				vertices++;
				continue;
			}

			// First tangent
			point = vertices->xyz + vertices->tangents[0] * r_showNormals->floatValue;

			qglColor3f(1.0f, 0.0f, 0.0f);
			qglVertex3fv(vertices->xyz.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			// Second tangent
			point = vertices->xyz + vertices->tangents[1] * r_showNormals->floatValue;

			qglColor3f(0.0f, 1.0f, 0.0f);
			qglVertex3fv(vertices->xyz.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			vertices++;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowTextureVectors
 ==================
*/
static void RB_ShowTextureVectors (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	glIndex_t	*indices;
	glVertex_t	*vertices;
	odVec3		center, point;
	odVec3		normal, tangents[2];
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Enable(GL_DEPTH_TEST);
	GL_DepthFunc(GL_LEQUAL);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Skip if it doesn't have texture vectors
		if (type != MESH_SURFACE && type != MESH_MODEL && type != MESH_FOLIAGE)
			continue;

		// Skip if it has a deform that invalidates the texture vectors
		if (material->deform == DFRM_SPRITE || material->deform == DFRM_TUBE || material->deform == DFRM_FLARE)
			continue;

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);

		// Render the texture vectors
		indices = backEnd.indices;
		vertices = backEnd.vertices;

		RB_Deform();

		qglBegin(GL_LINES);
		for (j = 0; j < backEnd.numIndices; j += 3){
			// Compute center of triangle
			center = ((vertices[indices[0]].xyz + vertices[indices[1]].xyz + vertices[indices[2]].xyz) * (1.0f/3));

			// Compute triangle normal
			normal = vertices[indices[0]].normal + vertices[indices[1]].normal + vertices[indices[2]].normal;
			normal.NormalizeFast();

			// Offset the center
			center += normal * 0.1f;

			// First tangent
			tangents[0] = vertices[indices[0]].tangents[0] + vertices[indices[1]].tangents[0] + vertices[indices[2]].tangents[0];
			tangents[0].NormalizeFast();

			point = center + tangents[0] * r_showTextureVectors->floatValue;

			qglColor3f(1.0f, 0.0f, 0.0f);
			qglVertex3fv(center.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			// Second tangent
			tangents[1] = vertices[indices[0]].tangents[1] + vertices[indices[1]].tangents[1] + vertices[indices[2]].tangents[1];
			tangents[1].NormalizeFast();

			point = center + tangents[1] * r_showTextureVectors->floatValue;

			qglColor3f(0.0f, 1.0f, 0.0f);
			qglVertex3fv(center.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			indices += 3;
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();

		// Clear the arrays
		backEnd.numIndices = 0;
		backEnd.numVertices = 0;
	}
}

/*
 ==================
 RB_ShowBatchSizeColored
 ==================
*/
static void RB_ShowBatchSizeColored (void){

	glIndex_t	*indices;
	glVertex_t	*vertices;
	int			i;

	// Set the color based on triangle count
	if (backEnd.numIndices >= 1500)
		qglColor3f(0.0f, 1.0f, 0.0f);
	else if (backEnd.numIndices >= 300)
		qglColor3f(1.0f, 1.0f, 0.0f);
	else if (backEnd.numIndices >= 150)
		qglColor3f(1.0f, 0.5f, 0.0f);
	else if (backEnd.numIndices >= 30)
		qglColor3f(1.0f, 0.0f, 0.0f);
	else
		qglColor3f(1.0f, 0.0f, 1.0f);

	// Render the batch
	indices = backEnd.indices;
	vertices = backEnd.vertices;

	RB_Deform();

	qglBegin(GL_TRIANGLES);
	for (i = 0; i < backEnd.numIndices; i += 3){
		qglVertex3fv(vertices[indices[0]].xyz.ToFloatPtr());
		qglVertex3fv(vertices[indices[1]].xyz.ToFloatPtr());
		qglVertex3fv(vertices[indices[2]].xyz.ToFloatPtr());

		indices += 3;
	}
	qglEnd();
}

/*
 ==================
 RB_ShowBatchSize
 ==================
*/
static void RB_ShowBatchSize (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	uint		sort = 0;
	material_t	*material, *oldMaterial = NULL;
	entity_t	*entity, *oldEntity = NULL;
	meshType_t	type;
	bool		caps;
	bool		skip;
	int			i;

	if (!numDrawMeshes)
		return;

	// Set the render function
	backEnd.renderBatch = RB_ShowBatchSizeColored;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	if (r_showBatchSize->integerValue == 1){
		GL_Enable(GL_DEPTH_TEST);
		GL_DepthFunc(GL_LEQUAL);
	}
	else
		GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	if (r_showBatchSize->integerValue == 1){
		GL_Enable(GL_POLYGON_OFFSET_LINE);
		GL_PolygonOffset(r_offsetFactor->floatValue, r_offsetUnits->floatValue);
	}

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		if (drawMesh->sort != sort){
			sort = drawMesh->sort;

			// Render the last batch
			RB_EndBatch();

			// Decompose sort
			R_DecomposeSort(backEnd.scene, sort, &material, &entity, &type, &caps);

			// Evaluate registers if needed
			if (material != oldMaterial || entity != oldEntity)
				R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!material->expressionRegisters[material->conditionRegister]){
				skip = true;
				continue;
			}

			// Set the entity state if needed
			if (entity != oldEntity)
				RB_SetEntityState(entity);

			// Create a new batch
			RB_BeginBatch(material, entity, false, false);

			oldMaterial = material;
			oldEntity = entity;

			skip = false;
		}

		if (skip)
			continue;

		// Batch the mesh
		RB_BatchMesh(type, drawMesh->mesh);
	}

	// Render the last batch
	RB_EndBatch();

	// Restore the GL state
	if (r_showBatchSize->integerValue == 1)
		GL_Disable(GL_POLYGON_OFFSET_LINE);

	qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

/*
static void RB_ShowSkeletons (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	md5Model_t	*model;
	odJointMat	*joint, joints[MD5_MAX_JOINTS];
	odVec3		point;
	int			parent;
	int			i, j;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Skip if world entity or not a model
		if (entity == backEnd.scene->worldEntity || entity->e.type != RE_MODEL)
			continue;

		// Skip if not a skeletal model
		if (!entity->e.model || entity->e.model->type != MODEL_MD5)
			continue;

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Render the skeleton
		model = (md5Model_t *)entity->e.model->data;

		if (entity->e.joints){
			for (j = 0; j < model->numJoints; j++)
				joints[j] = entity->e.joints[j];
		}
		else {
			for (j = 0; j < model->numJoints; j++)
				joints[j] = -model->joints[j].matrix;
		}

		qglBegin(GL_LINES);
		for (j = 0, joint = joints; j < model->numJoints; j++, joint++){
			parent = model->joints[j].parent;

			// Origin
			if (parent >= 0){
				qglColor3f(1.0f, 1.0f, 1.0f);
				qglVertex3fv(joint->translation.ToFloatPtr());
				qglVertex3fv(joints[parent].translation.ToFloatPtr());
			}

			// Axes
			point = joint->translation + joint->rotation[0] * r_showSkeletons->floatValue;

			qglColor3f(1.0f, 0.0f, 0.0f);
			qglVertex3fv(joint->translation.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			point = joint->translation + joint->rotation[1] * r_showSkeletons->floatValue;

			qglColor3f(0.0f, 1.0f, 0.0f);
			qglVertex3fv(joint->translation.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());

			point = joint->translation + joint->rotation[2] * r_showSkeletons->floatValue;

			qglColor3f(0.0f, 0.0f, 1.0f);
			qglVertex3fv(joint->translation.ToFloatPtr());
			qglVertex3fv(point.ToFloatPtr());
		}
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();
	}
}
*/
/*
 ==================
 RB_ShowModelBounds
 ==================
*/
static void RB_ShowModelBounds (int numDrawMeshes, drawMesh_t *drawMeshes){

	drawMesh_t	*drawMesh;
	material_t	*material;
	entity_t	*entity;
	meshType_t	type;
	bool		caps;
	model_t		*model;
	odVec3		corners[8];
	int			i;

	if (!numDrawMeshes)
		return;

	// Set the GL state
	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Disable(GL_STENCIL_TEST);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(0);

	qglColor3f(1.0f, 1.0f, 1.0f);

	// Run through the meshes
	for (i = 0, drawMesh = drawMeshes; i < numDrawMeshes; i++, drawMesh++){
		// Decompose sort
		R_DecomposeSort(backEnd.scene, drawMesh->sort, &material, &entity, &type, &caps);

		// Skip if world entity or not a model
		if (entity == backEnd.scene->worldEntity || entity->e.type != RE_MODEL)
			continue;

		// Skip if NULL or bad model
		if (!entity->e.model || entity->e.model->type == MODEL_BAD)
			continue;

		// Evaluate registers
		R_EvaluateRegisters(material, backEnd.time, entity->e.materialParms, backEnd.materialParms);

		// Skip if condition evaluated to false
		if (!material->expressionRegisters[material->conditionRegister])
			continue;

		// Set the entity state
		RB_SetEntityState(entity);

		// Set the batch state
		backEnd.material = material;
		backEnd.entity = entity;

		backEnd.shadowVolume = false;
		backEnd.shadowCaps = false;

		// Render the model bounds
		model = entity->e.model;

		switch (entity->e.model->type){
		case MODEL_INLINE:
			((inlineModel_t *)model->data)->bounds.ToPoints(corners);

			break;
		case MODEL_MDL:
			((mdlModel_t *)model->data)->bounds.ToPoints(corners);

			break;
		case MODEL_MD5:
			if (entity->instance)
				entity->instance->bounds.ToPoints(corners);
			else
				entity->e.bounds.ToPoints(corners);

			break;
		}

		qglBegin(GL_LINE_LOOP);
		qglVertex3fv(corners[0].ToFloatPtr());
		qglVertex3fv(corners[2].ToFloatPtr());
		qglVertex3fv(corners[3].ToFloatPtr());
		qglVertex3fv(corners[1].ToFloatPtr());
		qglEnd();

		qglBegin(GL_LINE_LOOP);
		qglVertex3fv(corners[4].ToFloatPtr());
		qglVertex3fv(corners[6].ToFloatPtr());
		qglVertex3fv(corners[7].ToFloatPtr());
		qglVertex3fv(corners[5].ToFloatPtr());
		qglEnd();

		qglBegin(GL_LINES);
		qglVertex3fv(corners[0].ToFloatPtr());
		qglVertex3fv(corners[4].ToFloatPtr());
		qglVertex3fv(corners[1].ToFloatPtr());
		qglVertex3fv(corners[5].ToFloatPtr());
		qglVertex3fv(corners[2].ToFloatPtr());
		qglVertex3fv(corners[6].ToFloatPtr());
		qglVertex3fv(corners[3].ToFloatPtr());
		qglVertex3fv(corners[7].ToFloatPtr());
		qglEnd();

		// Check for errors
		if (!r_ignoreGLErrors->integerValue)
			GL_CheckForErrors();
	}
}

/*
 ==================
 RB_ShowStencil
 ==================
*/
static float RB_ShowStencil (void){

	byte	*buffer;
	int		overdraw = 0;
	int		i;

	// Set the GL state
	GL_LoadIdentity(GL_MODELVIEW);

	GL_DisableTexture();

	GL_Disable(GL_CULL_FACE);

	GL_Disable(GL_POLYGON_OFFSET_FILL);

	GL_Disable(GL_BLEND);

	GL_Disable(GL_ALPHA_TEST);

	GL_Disable(GL_DEPTH_TEST);

	GL_Enable(GL_STENCIL_TEST);
	GL_StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_FALSE);
	GL_StencilMask(255);

	GL_DepthRange(0.0f, 1.0f);

	// Draw fullscreen quads
	qglMatrixMode(GL_PROJECTION);
	qglPushMatrix();
	qglLoadIdentity();

	for (i = 0; i <= 7; i++){
		if (i == 7)
			GL_StencilFunc(GL_LEQUAL, i, 255);
		else
			GL_StencilFunc(GL_EQUAL, i, 255);

		qglColor4fv(colorTable[i].ToFloatPtr());

		qglBegin(GL_QUADS);
		qglVertex3f(-1.0f, -1.0f, -1.0f);
		qglVertex3f( 1.0f, -1.0f, -1.0f);
		qglVertex3f( 1.0f,  1.0f, -1.0f);
		qglVertex3f(-1.0f,  1.0f, -1.0f);
		qglEnd();
	}

	qglMatrixMode(GL_PROJECTION);
	qglPopMatrix();

	// Read the stencil buffer
	buffer = (byte *)Mem_Alloc(backEnd.viewParms.width * backEnd.viewParms.height, TAG_TEMP);

	qglReadPixels(backEnd.viewParms.x, backEnd.viewParms.y, backEnd.viewParms.width, backEnd.viewParms.height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer);

	// Measure overdraw
	for (i = 0; i < backEnd.viewParms.width * backEnd.viewParms.height; i++)
		overdraw += buffer[i];

	Mem_Free(buffer);

	// Check for errors
	if (!r_ignoreGLErrors->integerValue)
		GL_CheckForErrors();

	return overdraw / (float)(backEnd.viewParms.width * backEnd.viewParms.height);
}

/*
 ==================
 RB_RenderDebugTools
 ==================
*/
void RB_RenderDebugTools (const renderViewCommand_t *cmd){

	int		i, j;

	if (backEnd.viewParms.bloom)
		return;

	if (r_logFile->integerValue)
		QGL_LogPrintf("---------- RB_RenderDebugTools ----------\n");

	// Set debug tools mode
	backEnd.debugTools = true;

	// Render debug tools
	if (r_showDepth->integerValue)
		RB_ShowDepth();

	if (r_showOverdraw->integerValue){
		// Clear the stencil buffer
		GL_StencilMask(255);

		qglClearStencil(0);
		qglClear(GL_STENCIL_BUFFER_BIT);

		if (r_showOverdraw->integerValue != 2){
			RB_ShowOverdraw(cmd->numDrawMeshes, cmd->drawMeshes, true, false);
			RB_ShowOverdraw(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes, true, false);
		}

		if (r_showOverdraw->integerValue != 1){
			// Run through the lights
			for (i = 0, backEnd.light = cmd->drawLights; i < cmd->numDrawLights; i++, backEnd.light++){
				// Set the light material
				backEnd.lightMaterial = backEnd.light->material;

				// Evaluate registers
				R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

				// Skip if condition evaluated to false
				if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
					continue;

				// Set the scissor rectangle
				qglScissor(backEnd.light->scissorX, backEnd.light->scissorY, backEnd.light->scissorWidth, backEnd.light->scissorHeight);

				// Set the depth bounds
				if (glConfig.depthBoundsTestAvailable)
					qglDepthBoundsEXT(backEnd.light->depthMin, backEnd.light->depthMax);

				// Run through the light stages
				for (j = 0, backEnd.lightStage = backEnd.lightMaterial->stages; j < backEnd.lightMaterial->numStages; j++, backEnd.lightStage++){
					if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightStage->conditionRegister])
						continue;

					// Run through the meshes
					RB_ShowOverdraw(backEnd.light->numInteractionMeshes[0], backEnd.light->interactionMeshes[0], false, false);
					RB_ShowOverdraw(backEnd.light->numInteractionMeshes[1], backEnd.light->interactionMeshes[1], false, false);
				}
			}

			// Run through the lights
			for (i = 0, backEnd.light = cmd->drawFogLights; i < cmd->numDrawFogLights; i++, backEnd.light++){
				// Set the light material
				backEnd.lightMaterial = backEnd.light->material;

				// Evaluate registers
				R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

				// Skip if condition evaluated to false
				if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
					continue;

				// Set the scissor rectangle
				qglScissor(backEnd.light->scissorX, backEnd.light->scissorY, backEnd.light->scissorWidth, backEnd.light->scissorHeight);

				// Set the depth bounds
				if (glConfig.depthBoundsTestAvailable)
					qglDepthBoundsEXT(backEnd.light->depthMin, backEnd.light->depthMax);

				// Run through the light stages
				for (j = 0, backEnd.lightStage = backEnd.lightMaterial->stages; j < backEnd.lightMaterial->numStages; j++, backEnd.lightStage++){
					if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightStage->conditionRegister])
						continue;

					// Run through the meshes
					RB_ShowOverdraw(backEnd.light->numInteractionMeshes[0], backEnd.light->interactionMeshes[0], false, true);
				}
			}

			// Restore the scissor rectangle
			qglScissor(backEnd.viewParms.x, backEnd.viewParms.y, backEnd.viewParms.width, backEnd.viewParms.height);

			// Restore the depth bounds
			if (glConfig.depthBoundsTestAvailable)
				qglDepthBoundsEXT(0.0f, 1.0f);
		}

		// Draw the stencil buffer contents
		tr.pc.overdraw += RB_ShowStencil();
	}

	if (r_showShadowCount->integerValue){
		// Clear the stencil buffer
		GL_StencilMask(255);

		qglClearStencil(0);
		qglClear(GL_STENCIL_BUFFER_BIT);

		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawLights; i < cmd->numDrawLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Set the scissor rectangle
			qglScissor(backEnd.light->scissorX, backEnd.light->scissorY, backEnd.light->scissorWidth, backEnd.light->scissorHeight);

			// Set the depth bounds
			if (glConfig.depthBoundsTestAvailable)
				qglDepthBoundsEXT(backEnd.light->depthMin, backEnd.light->depthMax);

			// Run through the meshes
			RB_ShowShadowCount(backEnd.light->numShadowMeshes[0], backEnd.light->shadowMeshes[0]);
			RB_ShowShadowCount(backEnd.light->numShadowMeshes[1], backEnd.light->shadowMeshes[1]);
		}

		// Restore the scissor rectangle
		qglScissor(backEnd.viewParms.x, backEnd.viewParms.y, backEnd.viewParms.width, backEnd.viewParms.height);

		// Restore the depth bounds
		if (glConfig.depthBoundsTestAvailable)
			qglDepthBoundsEXT(0.0f, 1.0f);

		// Draw the stencil buffer contents
		tr.pc.overdrawShadows += RB_ShowStencil();
	}

	if (r_showLightCount->integerValue){
		// Clear the stencil buffer
		GL_StencilMask(255);

		qglClearStencil(0);
		qglClear(GL_STENCIL_BUFFER_BIT);

		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawLights; i < cmd->numDrawLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Set the scissor rectangle
			qglScissor(backEnd.light->scissorX, backEnd.light->scissorY, backEnd.light->scissorWidth, backEnd.light->scissorHeight);

			// Set the depth bounds
			if (glConfig.depthBoundsTestAvailable)
				qglDepthBoundsEXT(backEnd.light->depthMin, backEnd.light->depthMax);

			// Run through the meshes
			RB_ShowLightCount(backEnd.light->numInteractionMeshes[0], backEnd.light->interactionMeshes[0]);
			RB_ShowLightCount(backEnd.light->numInteractionMeshes[1], backEnd.light->interactionMeshes[1]);
		}

		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawFogLights; i < cmd->numDrawFogLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Set the scissor rectangle
			qglScissor(backEnd.light->scissorX, backEnd.light->scissorY, backEnd.light->scissorWidth, backEnd.light->scissorHeight);

			// Set the depth bounds
			if (glConfig.depthBoundsTestAvailable)
				qglDepthBoundsEXT(backEnd.light->depthMin, backEnd.light->depthMax);

			// Run through the meshes
			RB_ShowLightCount(backEnd.light->numInteractionMeshes[0], backEnd.light->interactionMeshes[0]);
		}

		// Restore the scissor rectangle
		qglScissor(backEnd.viewParms.x, backEnd.viewParms.y, backEnd.viewParms.width, backEnd.viewParms.height);

		if (glConfig.depthBoundsTestAvailable)
			qglDepthBoundsEXT(0.0f, 1.0f);

		// Draw the stencil buffer contents
		tr.pc.overdrawLights += RB_ShowStencil();
	}

	if (r_showLightVolumes->integerValue){
		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawLights; i < cmd->numDrawLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Draw the light volume
			RB_ShowLightVolume();
		}

		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawFogLights; i < cmd->numDrawFogLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Draw the light volume
			RB_ShowLightVolume();
		}
	}

	if (r_showLightScissors->integerValue){
		// Set the GL state
		GL_LoadIdentity(GL_MODELVIEW);

		GL_DepthRange(0.0f, 1.0f);

		qglMatrixMode(GL_PROJECTION);
		qglPushMatrix();
		qglLoadIdentity();
		qglOrtho(backEnd.viewParms.x, backEnd.viewParms.x + backEnd.viewParms.width, backEnd.viewParms.y, backEnd.viewParms.y + backEnd.viewParms.height, -1.0, 1.0);

		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawLights; i < cmd->numDrawLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Draw the light scissors
			RB_ShowLightScissors();
		}

		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawFogLights; i < cmd->numDrawFogLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Draw the light scissors
			RB_ShowLightScissors();
		}

		// Restore the GL state
		qglMatrixMode(GL_PROJECTION);
		qglPopMatrix();
	}

	if (r_showShadowTris->integerValue || r_showShadowVolumes->integerValue || r_showShadowSilhouettes->integerValue){
		// Run through the lights
		for (i = 0, backEnd.light = cmd->drawLights; i < cmd->numDrawLights; i++, backEnd.light++){
			// Set the light material
			backEnd.lightMaterial = backEnd.light->material;

			// Evaluate registers
			R_EvaluateRegisters(backEnd.lightMaterial, backEnd.time, backEnd.light->materialParms, backEnd.materialParms);

			// Skip if condition evaluated to false
			if (!backEnd.lightMaterial->expressionRegisters[backEnd.lightMaterial->conditionRegister])
				continue;

			// Set the scissor rectangle
			qglScissor(backEnd.light->scissorX, backEnd.light->scissorY, backEnd.light->scissorWidth, backEnd.light->scissorHeight);

			// Set the depth bounds
			if (glConfig.depthBoundsTestAvailable)
				qglDepthBoundsEXT(backEnd.light->depthMin, backEnd.light->depthMax);

			// Run through the meshes
			if (r_showShadowTris->integerValue){
				RB_ShowShadowTris(backEnd.light->numShadowMeshes[0], backEnd.light->shadowMeshes[0]);
				RB_ShowShadowTris(backEnd.light->numShadowMeshes[1], backEnd.light->shadowMeshes[1]);
			}

			if (r_showShadowVolumes->integerValue){
				RB_ShowShadowVolumes(backEnd.light->numShadowMeshes[0], backEnd.light->shadowMeshes[0]);
				RB_ShowShadowVolumes(backEnd.light->numShadowMeshes[1], backEnd.light->shadowMeshes[1]);
			}

			if (r_showShadowSilhouettes->integerValue){
				RB_ShowShadowSilhouettes(backEnd.light->numShadowMeshes[0], backEnd.light->shadowMeshes[0]);
				RB_ShowShadowSilhouettes(backEnd.light->numShadowMeshes[1], backEnd.light->shadowMeshes[1]);
			}
		}

		// Restore the scissor rectangle
		qglScissor(backEnd.viewParms.x, backEnd.viewParms.y, backEnd.viewParms.width, backEnd.viewParms.height);

		// Restore the depth bounds
		if (glConfig.depthBoundsTestAvailable)
			qglDepthBoundsEXT(0.0f, 1.0f);
	}

	if (r_showVertexColors->integerValue){
		RB_ShowVertexColors(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowVertexColors(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

	if (r_showTangentSpace->integerValue){
		RB_ShowTangentSpace(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowTangentSpace(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

	if (r_showTris->integerValue){
		RB_ShowTris(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowTris(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

	if (r_showNormals->floatValue){
		RB_ShowNormals(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowNormals(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

	if (r_showTextureVectors->floatValue){
		RB_ShowTextureVectors(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowTextureVectors(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

	if (r_showBatchSize->integerValue){
		RB_ShowBatchSize(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowBatchSize(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

//	if (r_showSkeletons->integerValue){
//		RB_ShowSkeletons(cmd->numDrawMeshes, cmd->drawMeshes);
//		RB_ShowSkeletons(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
//	}

	if (r_showModelBounds->integerValue){
		RB_ShowModelBounds(cmd->numDrawMeshes, cmd->drawMeshes);
		RB_ShowModelBounds(cmd->numDrawPostProcessMeshes, cmd->drawPostProcessMeshes);
	}

	// Refresh an editor if active
	if (backEnd.viewParms.primaryView && backEnd.viewParms.viewType == VIEW_MAIN)
		ED_Refresh();

	// Clear debug tools mode
	backEnd.debugTools = false;
}
